<?php

namespace App\Services;

use Config;
use App\Services\Openssl\AccountBooksException;
use App\Services\Array2XML;

/*
 * 账册服务
 */
class AccountBooks {

    protected $config;

    function __construct()
    {
        $config = config('account-books');
        $this->config = $config;

    }

    /** 设置参数
     * @param $key
     * @param $value
     */
    public function setParam($key,$value){

        $this->params[$key] = $value;

    }//end func setParam


    /*
     * 根据商品信息数组进行请求
     */
    public function sendPost($goods, $dcrTimes, $start_date, $end_date){

        $xmlGoods ='<?xml version="1.0" encoding="utf-8"?>
            <StoreCompareMessageOuter xmlns="http://www.cneport.com/blc/storeCompare/domain/message/outer">
            <StoreCompareHeadOuter>
                <LmsNo>'.$this->config['lmsNo'].'</LmsNo>
                <DcrTimes>'.$dcrTimes.'</DcrTimes>
                <BeginDate>'.$start_date.'</BeginDate>
                <EndDate>'.$end_date.'</EndDate>
                <AppTime></AppTime>//非必填
                <TradeCode>'.$this->config['tradeCode'].'</TradeCode>
                <TradeName>'.$this->config['tradeName'].'</TradeName>
                <AppUid></AppUid>
                <AppUname></AppUname>
                <CustomsCode>'.$this->config['customsCode'].'</CustomsCode>
                <FileTotal></FileTotal>
                <FileNo></FileNo>
                <ModifyMark>'.$this->config['modifyMark'].'</ModifyMark>
                <Note></Note>
            </StoreCompareHeadOuter>
            <GoodsList>';

            foreach ($goods as $key=>$goodsInfo) {
                $xmlGoods .=  '<StoreCompareGoodsOuter>
                      <LmsNo>'.$this->config['lmsNo'].'</LmsNo>
                      <CbeCode>'.$this->config['cbeCode'].'</CbeCode>
                      <CbeName>'.$this->config['cbeName'].'</CbeName>
                      <ItemNo></ItemNo>
                      <GoodsNo>'.$goodsInfo['goods_sn'].'</GoodsNo>
                      <TaxCode></TaxCode>
                      <CodeTs>'.$goodsInfo['goods_sn'].'</CodeTs>
                      <GoodsName>'.$goodsInfo['goods_name'].'</GoodsName>
                      <Unit>'.$goodsInfo['unitCiq'].'</Unit>
                      <Note></Note>
                      <LegalInQty>'.$goodsInfo['legalInQty'].'</LegalInQty>
                      <LegalOutQty>'.$goodsInfo['legalOutQty'].'</LegalOutQty>
                      <InventoryCarryInQty></InventoryCarryInQty>
                      <InventoryTurnOutQty></InventoryTurnOutQty>
                      <LegalRemainQty>'.$goodsInfo['legalRemainQty'].'</LegalRemainQty>
                      <RealRemainQty>'.$goodsInfo['realRemainQty'].'</RealRemainQty>
                      <PeriodStartQty>'.$goodsInfo['periodStartQty'].'</PeriodStartQty>
                      <StoreInfo>'.$goodsInfo['storeInfo'].'</StoreInfo>
                  </StoreCompareGoodsOuter>';
            }//end foreach

            $xmlGoods .= '</GoodsList>
        </StoreCompareMessageOuter>';


        $signedDataInfo = $this->encryption($xmlGoods);

        $request = [
            'PubInfo' => [
                'Version' => ['@value' => $this->config['version']],//Webservice接口版本
                'CompanyCode' => $this->config['companyCode'],//发送企业编号
                'Key' => $this->config['key'],//发送企业Key；用于身份识别
                'MsgType' => 'S',//报文类型,O-订单；W-运单；T-妥投；S-账册
                'OptType' => 1,//操作类型,1-新增；2-修改
                'Signature' => $this->md5($signedDataInfo),//验证加密报文是否一致  数据签名细节：已加密订单信息字符串以“UTF-8”编码转成字节数组后经MD5摘要算法得出32位摘要签名。
                'CreatTime' => date('Y-m-d H:i:s'),//单据生成日期
            ],
            'DataInfo' => [
                '@cdata' => $signedDataInfo
            ]
        ];

        $requestXml = Array2XML::createXML('Root', $request)->saveXML();

        return $this->makeRequest($this->config['url'], ['xml' => $requestXml]);




    }//end func sendPost

    /*
     * 加密账册报文信息格式
     *
     * 请求报文中DataInfo节点内容是订单信息加密后的密文，加密方式为RSA加密，公钥由E贸易提供。
     * 加密过程细节：订单XML字符串以UTF-8编码格式转换成字节数组进行RSA加密，加密后数组经BASE64编码转换为最终密文字符串
     */
    public function encryption($data){

        $public_key_str = $this->config['publicKey'];

        if (empty($data)) {
            return null;
        }
        $pem = "-----BEGIN PUBLIC KEY-----\n" . chunk_split($public_key_str, 64, "\n") . "-----END PUBLIC KEY-----\n";
        $key = openssl_pkey_get_public($pem);
        $resultb = "";
        $dataArray = str_split($data, 117);
        foreach ($dataArray as $d) {
            if (openssl_public_encrypt($d, $encrypted, $key)) {
                $resultb .= $encrypted;
            } else return null;
        }
        return base64_encode($resultb);
    }//end func encryption


    /**
     * 字符串转字节数组
     * @param $string
     * @return array
     */
     function getBytes($string) {
        $bytes = array();
        for($i = 0; $i < strlen($string); $i++){
            $bytes[] = ord($string[$i]);
        }
        return $bytes;
    }


    /**
     * 构建请求
     * @param string $data
     * @param string $url
     * @return mixed|string
     */
    private function makeRequest($url, $data)
    {
        try {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
            $response = curl_exec($ch);

        }catch (\Exception $e){

            throw new AccountBooksException($e->getMessage());
        }
        $repsonXmlObj = simplexml_load_string($response);

        if($repsonXmlObj->Status=='0'){

            return true;
        }
        else{
            throw new AccountBooksException($repsonXmlObj->Detail);
        }



    }//end func makeRequest

    /**数字签名**/

    public function md5($data)
    {
        $xt = md5($data);
        return $xt;
    }

}